package com.yuanqi.Service.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yuanqi.Common.Expriess.BaseException;
import com.yuanqi.Common.Pojo.Dto.UserInfoDto;
import com.yuanqi.Common.Pojo.Vo.*;
import com.yuanqi.Common.Pojo.entity.Follow;
import com.yuanqi.Common.config.ThreadLocalConfig;
import com.yuanqi.Mapper.FollowMapper;
import com.yuanqi.Mapper.UserBindMapper;
import com.yuanqi.Mapper.UserInfoMapper;
import com.yuanqi.Mapper.UserMapper;
import com.yuanqi.Common.Pojo.Dto.UserDto;
import com.yuanqi.Common.Pojo.entity.User;
import com.yuanqi.Common.Pojo.entity.UserBind;
import com.yuanqi.Common.Pojo.entity.Userinfo;
import com.yuanqi.Properties.JwtProperties;
import com.yuanqi.Service.UserService;
import com.yuanqi.Utils.AliCaptcha;
import com.yuanqi.Utils.JwtUtil;
import org.mindrot.jbcrypt.BCrypt;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    StringRedisTemplate stringRedisTemplate;

    @Resource
    AliCaptcha aliCaptcha;

    @Resource
    UserMapper userMapper;
    @Resource
    UserBindMapper userBindMapper;
    @Resource
    private JwtProperties jwtProperties;

    @Resource
    ThreadPoolExecutor threadPoolExecutor;

    @Resource
    ThreadLocalConfig threadLocalConfig;

    @Resource
    UserInfoMapper userInfoMapper;
    @Resource
    FollowMapper followMapper;

    /**
     * 获取手机验证码
     *
     * @param phone
     */
    @Override
    public String phoneCaptcha(String phone) {
        //检查手机格式
        Boolean b = checkPhone(phone);
        if (!b) {
            throw new BaseException("手机格式不正确");
        }
        //判断是否在60s内已经发送过验证码
        String phone1 = stringRedisTemplate.opsForValue().get(phone);
        if (ObjectUtil.isNotEmpty(phone1)) {
            throw new BaseException("请勿频繁发送验证码");
        }
        String substring = UUID.randomUUID().toString().substring(0, 4);
        //发送验证码
        try {
            aliCaptcha.send(phone, substring);
            //成功储存验证码并返回
            stringRedisTemplate.opsForValue().set(phone, substring, 60, TimeUnit.SECONDS);
            return substring;
        } catch (Exception e) {
            throw new BaseException("消息发送失败");
        }
    }

    @Override
    public UserLoginVo phonelogin(UserDto user) {

        extracted(user.getPhone(), user.getCode());

        LambdaQueryWrapper<User> eq = new LambdaQueryWrapper<User>().eq(User::getPhone, user.getPhone());
        User user1 = userMapper.selectOne(eq);
        //用户不存在就注册
        if (ObjectUtil.isEmpty(user1)) {
            //获取时间戳
            Long time = System.currentTimeMillis() / 1000;
            user1 = new User();
            user1.setPhone(user.getPhone());
            user1.setStatus(1);
            user1.setCreate_time(time);
            user1.setUsername(user.getPhone());
            userMapper.insert(user1);
            Userinfo userinfo = new Userinfo();
            userinfo.setUserId(user1.getId());
            userInfoMapper.insert(userinfo);
        } else if (user1.getStatus() == 0) {
            throw new BaseException("用户被禁用了");
        }
        String token = getToken(user1);
        return new UserLoginVo(token, user1);
    }


    /**
     * 账号密码登录
     *
     * @param user
     * @return
     */

    @Override
    public UserLoginVo UsernameLogin(UserDto user) {
        //判断用户是否存在
        User user1 = isexit(user);
        if (ObjectUtil.isEmpty(user1)) {
            throw new BaseException("用户不存在");
        } else if (user1.getStatus() == 0) {
            throw new BaseException("用户被禁用了");
        }
        boolean checkpw = BCrypt.checkpw(user.getPassword(), user1.getPassword());
        if (!checkpw) {
            throw new BaseException("密码错误");
        }
        String token = getToken(user1);
        return new UserLoginVo(token, user1);
    }

    @Override
    public UserLoginVo otherlogin(UserBind user) {
        UserDto bean = BeanUtil.toBean(user, UserDto.class);
        User isexit1 = isexit(bean);
        //用户不存在就注册
        if (ObjectUtil.isEmpty(isexit1)) {
            throw new BaseException("请绑定手机号");
        } else {
            //用户存在
            if (isexit1.getStatus() == 0) {
                throw new BaseException("用户被禁用了");
            }
            String token = getToken(isexit1);

            return new UserLoginVo(token, isexit1);
        }
    }

    @Override
    public UserLoginVo otherBind(UserDto user) {
        String phone = user.getPhone();
        //验证手机验证码
        extracted(phone, user.getCode());
        //查询用户手机号是否注册过
        LambdaQueryWrapper<User> eq = new LambdaQueryWrapper<User>().eq(User::getPhone, phone);
        User user1 = userMapper.selectOne(eq);
        //用户不存在就注册

        if (ObjectUtil.isEmpty(user1)) {
            //获取时间戳
            Long time = System.currentTimeMillis() / 1000;
            user1 = User.builder().phone(user.getPhone()).status(1).create_time(time).
                    username(user.getPhone()).build();
            userMapper.insert(user1);
            //绑定第三方账号
            UserBind build1 = UserBind.builder().type(user.getType()).openid(user.getOpenid()).avatarurl(user.getAvatarurl()).nickname(user.getNickName()).build();
            userBindMapper.insert(build1);
        } else if (user1.getStatus() == 0) {
            throw new BaseException("绑定的用户被禁用了");
        } else {
            //用户存在
            //查询用户下绑定的账号
            LambdaQueryWrapper<UserBind> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserBind::getUserId, user1.getId());
            List<UserBind> userBinds = userBindMapper.selectList(wrapper);
            List<String> type = userBinds.stream().map(res -> res.getType()).collect(Collectors.toList());
            if (type.contains(user.getType())) {
                throw new BaseException("该手机已经绑定了" + user.getType() + "相关账号");
            } else {
                UserBind build = UserBind.builder().type(user.getType()).openid(user.getOpenid()).avatarurl(user.getAvatarurl()).nickname(user.getNickName()).userId(user1.getId()).build();
                userBindMapper.insert(build);
            }
        }

        return new UserLoginVo(getToken(user1), user1);
    }

    @Override
    public void updatapass(UserDto user) {
        extracted(user.getUsername(), user.getCode());
        User user1 = isexit(user);
        if (ObjectUtil.isEmpty(user1)) {
            throw new BaseException("用户不存在");
        } else if (user1.getStatus() == 0) {
            throw new BaseException("用户被禁用了");
        }
        String pw = BCrypt.hashpw(user.getPassword(), BCrypt.gensalt());
        user1.setPassword(pw);
        userMapper.updateById(user1);
    }

    @Override
    public List<UserVo> searchUser(UserDto userDto) throws InterruptedException {
        Page<User> page = new Page<>(userDto.getCurrent(), 10);
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(User::getNikeName, userDto.getNickName());
        wrapper.eq(User::getStatus, 1);
        Page<User> page1 = userMapper.selectPage(page, wrapper);
        List<User> records = page1.getRecords();

        ArrayList<UserVo> vos = new ArrayList<>();

        List<UserVo> userVos = records.stream().map((item) -> {
            return BeanUtil.toBean(item, UserVo.class);
        }).collect(Collectors.toList());
        //表示用户没有登录
        if (!userDto.getIsLogin()) {
            userVos.forEach((item) -> {
                item.setIsFollow(0);
            });
        } else {
            Long userId = userDto.getUserId();
            List<FollowVo> followVos = followMapper.eachOther(userId, null);
            List<FollowVo> flowers = followMapper.flowers(userId, null);
            userVos.forEach((item) -> {
                LambdaQueryWrapper<Follow> wrapper1 = new LambdaQueryWrapper<Follow>().eq(Follow::getUserId, userId).eq(Follow::getFollowId, item.getId());
                Follow follow1 = followMapper.selectOne(wrapper1);
                if (ObjectUtil.isEmpty(follow1)) {
                    item.setIsFollow(0);
                } else {
                    item.setIsFollow(1);
                }
//                这是粉丝
                if (!flowers.isEmpty())
                {
                    for (FollowVo flower : flowers) {
                        if (flower.getFollowId().equals(item.getId()))
                        {
                            item.setIsFollow(3);
                        }
                    }
                }
                if(!followVos.isEmpty())
                {
                    for (FollowVo followVo : followVos) {
                        if (followVo.getFollowId().equals(follow1.getFollowId())) {
                            item.setIsFollow(2);
                        }
                    }
                }

            });

        }

        CountDownLatch latch = new CountDownLatch(userVos.size());
        userVos.forEach((item) -> {
            threadPoolExecutor.execute(() -> {
                Userinfo userinfo = userMapper.selectUserInfo(item.getId());
                item.setUserinfo(userinfo);
                latch.countDown();
            });
        });
        latch.await();
        return userVos;
    }

    /**
     * 修改资料
     *
     *
     */
    @Override
    public void updateUserInfo(UserInfoDto userinfo2) {

        Long userId = Long.valueOf(threadLocalConfig.get().get("userId").toString());
        User user = new User();
        user.setId(userId);
        user.setUserpic(userinfo2.getImage());
        user.setNikeName(userinfo2.getName());
        userMapper.updateById(user);
        Userinfo userinfo = BeanUtil.toBean(userinfo2, Userinfo.class);
        userinfo.setUserId(userId);
        Userinfo userinfo1 = userInfoMapper.selectOne(new LambdaQueryWrapper<Userinfo>().eq(Userinfo::getUserId, userId));
        if (ObjectUtil.isEmpty(userinfo1)) {
            userInfoMapper.insert(userinfo);
        } else {
            userInfoMapper.update(userinfo, new LambdaQueryWrapper<Userinfo>().eq(Userinfo::getUserId, userId));
        }
    }

    @Override
    public UserPageVo getUserPage(Long userId) {
        return userMapper.getUserPage(userId);
    }

    @Override
    public UserPageVo getUserSpace(Long userId) {
        UserPageVo userPage = userMapper.getUserPage(userId);
        Userinfo userinfo = userMapper.selectUserInfo(userId);
        userPage.setUserinfo(userinfo);
        return userPage;
    }


    private User isexit(UserDto user) {
        //先看是否是手机号
        Boolean b = this.checkPhone(user.getUsername());
        if (b) {
            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(User::getPhone, user.getUsername());
            User user1 = userMapper.selectOne(wrapper);
            return user1;
        }
        //邮箱
        else if (this.checkEmail(user.getUsername())) {
            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(User::getEmail, user.getUsername());
            User user1 = userMapper.selectOne(wrapper);
            return user1;
        }
        //第三方
        else {
            String openid = user.getOpenid();
            if (openid == null) {
                return null;
            }
            UserBind userBind = userBindMapper.selectOne(new LambdaQueryWrapper<UserBind>().eq(UserBind::getOpenid, openid).eq(UserBind::getType, user.getType()));
            if (ObjectUtil.isEmpty(userBind)) return null;
            if (userBind.getUserId() > 0) {
                return userMapper.selectById(userBind.getUserId());
            } else return null;
        }

    }

    private String getToken(User user1) {
        HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("userId", user1.getId());
        String token = JwtUtil.CreateJwt(map, jwtProperties.getKey(), jwtProperties.getTime());
        stringRedisTemplate.opsForValue().set(user1.getId().toString(), token, jwtProperties.getTime(), TimeUnit.MILLISECONDS);
        return token;
    }

    private void extracted(String phone, String code1) {
        //验证验证码
        String code = stringRedisTemplate.opsForValue().get(phone);
        if (StrUtil.isEmpty(code)) {
            throw new BaseException("验证码不存在，请重新发送");
        } else if (!code.equals(code1)) {
            throw new BaseException("验证码输入错误");
        }
    }

    public Boolean checkPhone(String phone) {
        if (phone == null) return false;
        Pattern p = Pattern.compile("^((13[0-9])|(14[0|5|6|7|9])|(15[0|1|2|3|5|6|7|8|9])|(16[2|5|6|7])|(17[0|1|2|3|5|6|7|8])|(18[0-9])|(19[0|1|2|3|5|6|7|8|9]))\\d{8}$");
        Matcher m = p.matcher(phone);
        if (!m.matches()) {
            return false;
        }
        return true;
    }

    public Boolean checkEmail(String email) {
        if (email == null) return false;
        Pattern p = Pattern.compile("^[a-zA-Z0-9._%+-]+(?:\\.[a-zA-Z0-9._%+-]+)*@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}(?:\\.[a-zA-Z]{2,})?$");
        Matcher m = p.matcher(email);
        if (!m.matches()) {
            return false;
        }
        return true;
    }

}

